﻿using INOMVControl;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace Camera
{
    public class CameraINOVANCE : CameraBase
    {
        private string devSerialNumber;
        private IntPtr ifHandle, devHandle, dsHandle, remote_handle;
        private bool needStop;

        public override event ReadImageDelegate ReadImageEvent;
        public override event ConnectLossDelegate ConnectLossEvent;

        public CameraINOVANCE()
        {

        }

        public static string[] DeviceListAcq()
        {
            // 初始化所有汇川产品系列
            SDKSystem.Initialize((uint)INOV_ProductSeries.INOV_PRODUCT_SERIES_ALL);

            // 更新所有传输层接口
            SDKInterface.UpdateInterfaceList((uint)INOV_TransportLayerType.INOV_TL_TYPE_ALL, IntPtr.Zero, 2000);

            // 获取所有传输层接口信息
            INOV_INTERFACE_INFO_LIST ifInfoList;
            SDKInterface.GetInterfaceInfoList(out ifInfoList);

            // 显示并选择传输层接口
            if (ifInfoList.nInterfaceNum == 0)
            {
                return null;
            }

            List<string> list = new List<string>();
            for (uint i = 0; i < ifInfoList.nInterfaceNum; i++)
            {
                int elementSize = Marshal.SizeOf(typeof(INOV_INTERFACE_INFO));
                // 计算偏移量时，确保是 long 类型，避免溢出
                long offset = (long)i * elementSize;
                // 使用 IntPtr.Add 来进行指针偏移
                IntPtr currentElementPtr = IntPtr.Add(ifInfoList.pstInterfaceInfo, (int)offset);
                // 读取结构体数据
                INOV_INTERFACE_INFO info = (INOV_INTERFACE_INFO)Marshal.PtrToStructure(currentElementPtr, typeof(INOV_INTERFACE_INFO));

                string id = CString(info.szID);

                // 打开选择的传输层接口
                IntPtr ifHandle = info.hIFHandle;

                SDKInterface.OpenInterface(ifHandle);

                // 更新当前传输层接口上的所有设备
                Device.UpdateDeviceList(ifHandle, out _, 2000);

                // 获取当前传输层接口上的所有设备信息
                INOV_DEVICE_INFO_LIST devInfoList = new INOV_DEVICE_INFO_LIST();
                Device.GetDeviceInfoList(ifHandle, ref devInfoList);

                for (uint j = 0; j < devInfoList.nDeviceNum; j++)
                {
                    int devElementSize = Marshal.SizeOf(typeof(INOV_DEVICE_INFO));
                    long devOffset = (long)j * devElementSize;
                    IntPtr devCurrentElementPtr = IntPtr.Add(devInfoList.pstDeviceInfo, (int)devOffset);
                    INOV_DEVICE_INFO devInfo = (INOV_DEVICE_INFO)Marshal.PtrToStructure(devCurrentElementPtr, typeof(INOV_DEVICE_INFO));
                    Device.OpenDevice(devInfo.hDevHandle, INOV_DeviceAccessMode.INOV_DEVICE_ACCESS_MODE_CONTROL);
                    Device.GetDeviceInfo(devInfo.hDevHandle, ref devInfo);
                    string szSerialNumber = CString(devInfo.szSerialNumber);
                    list.Add($"{id}|{szSerialNumber}");
                    Device.CloseDevice(devInfo.hDevHandle);
                }

                // 关闭打开的传输层接口
                SDKInterface.CloseInterface(ifHandle);
            }
            return list.ToArray();
        }

        // 异常回调函数
        private void ExceptionCallback(INOV_EXCEPTION_INFO pstExceptionInfo, IntPtr pUser)
        {
            if (pstExceptionInfo.hDevHandle == IntPtr.Zero)
            {
                return;
            }

            if (pstExceptionInfo.nExceptionType == INOV_ExceptionType.INOV_DEVICE_EXCEPTION_TYPE_ACQUISITION_FAILURE)
            {
                // 开始采集失败应停止采集
                Stream.StopAcquisition(dsHandle);
            }
            else if (pstExceptionInfo.nExceptionType == INOV_ExceptionType.INOV_DEVICE_EXCEPTION_TYPE_RECONNECTED)
            {
                ConnectLossEvent("相机 " + devSerialNumber + " 异常掉线，重新连接中。。。");
                // 重新打开设备前先关闭之前的
                Device.CloseDevice(devHandle);

                // 可使用两种方法重新打开设备
                if (false)
                {
                    // 第一种：使用先前的设备句柄（请勿使用`INOV_UpdateDeviceList`更新设备列表，否则使用SDK内部将删除此句柄，导致句柄失效）
                    Device.OpenDevice(devHandle, INOV_DeviceAccessMode.INOV_DEVICE_ACCESS_MODE_CONTROL);
                }
                else
                {
                    Device.UpdateDeviceList(ifHandle, out _, 1000);
                    Device.OpenDeviceByID(ifHandle, devSerialNumber, out devHandle, INOV_DeviceAccessMode.INOV_DEVICE_ACCESS_MODE_CONTROL, INOV_IDType.INOV_ID_TYPE_AUTO);
                }

                // 注册异常回调函数
                Stream.RegisterExceptionCallback(devHandle, ExceptionCallback, IntPtr.Zero);

                // 打开第0个流通道
                IntPtr dsHandle = IntPtr.Zero;
                Stream.OpenStream(devHandle, 0, out dsHandle);

                // 向当前流通道注册取图回调函数
                Stream.RegisterFrameCallback(dsHandle, FrameCallBack, IntPtr.Zero);

                // 开始采集
                Stream.StartAcquisition(dsHandle, INOV_AcquisitionStrategy.INOV_ACQUISITION_STRATEGY_LATEST);
            }
            else if (pstExceptionInfo.nExceptionType == INOV_ExceptionType.INOV_DEVICE_EXCEPTION_TYPE_DISCONNECTED)
            {
                // 收到设备离线信号后请停止采集
                Stream.StopAcquisition(dsHandle);
            }
        }

        // 取图回调函数
        private void FrameCallBack(INOV_FRAME_INFO pstFrameInfo, IntPtr pUser)
        {
            // 在停止采集的時候来了下一帧
            if (needStop)
            {
                return;
            }
            ReadImageEvent(new Imgdata { data = pstFrameInfo.pBufPtr, width = (int)pstFrameInfo.nWidth, height = (int)pstFrameInfo.nHeight });
        }

        // 事件回调函数
        private void EventCallback(INOV_EVENT_INFO pstEventInfo, IntPtr pUser)
        {
            if (pstEventInfo.pEventData == IntPtr.Zero)
            {
                return;
            }
        }

        private static string CString(char[] arr)
        {
            int index = Array.IndexOf(arr, '\0');
            return index < 0 ? new string(arr) : new string(arr, 0, index);
        }

        public override bool Open(string devSerialNumber)
        {
            this.devSerialNumber = devSerialNumber;
            // 初始化所有汇川产品系列
            SDKSystem.Initialize((uint)INOV_ProductSeries.INOV_PRODUCT_SERIES_ALL);

            // 更新所有传输层接口
            SDKInterface.UpdateInterfaceList((uint)INOV_TransportLayerType.INOV_TL_TYPE_ALL, IntPtr.Zero, 2000);
            string[] szIdentifers = devSerialNumber.Split('|');
            SDKInterface.OpenInterfaceByID(szIdentifers[0], out ifHandle, (uint)INOV_IDType.INOV_ID_TYPE_ID);

            // 更新当前传输层接口上的所有设备
            Device.UpdateDeviceList(ifHandle, out _, 2000);

            // 通过ID打开设备(需在INOV_UpdateDeviceList 更新设备列表后)
            // Open device by id (after INOV_UpdateDeviceList)
            Device.OpenDeviceByID(ifHandle, szIdentifers[1], out devHandle, INOV_DeviceAccessMode.INOV_DEVICE_ACCESS_MODE_CONTROL, INOV_IDType.INOV_ID_TYPE_USER_ID);

            Device.RefreshDeviceRemotePort(devHandle, out remote_handle, 1000);

            // 注册事件回调函数
            Stream.RegisterEventCallback(devHandle, EventCallback, IntPtr.Zero);

            // 注册异常回调函数
            Stream.RegisterExceptionCallback(devHandle, ExceptionCallback, IntPtr.Zero);

            // 获取当前设备流通道个数
            uint streamNum = 0;
            Stream.GetStreamNum(devHandle, out streamNum);
            if (streamNum <= 0)
            {
                // 关闭设备/接口，回收SDK资源
                Device.CloseDevice(devHandle);
                SDKInterface.CloseInterface(ifHandle);
                SDKSystem.Finalize();
                return false;
            }

            // 打开第0个流通道
            Stream.OpenStream(devHandle, 0, out dsHandle);

            // 设置Buffer数量
            Stream.SetBufferNum(dsHandle, 4);

            // 向当前流通道注册取图回调函数
            Stream.RegisterFrameCallback(dsHandle, FrameCallBack, IntPtr.Zero);
            return true;
        }

        public override bool Close()
        {
            // 关闭打开的流通道
            Stream.CloseStream(dsHandle);

            // 关闭打开的设备
            Device.CloseDevice(devHandle);

            // 关闭打开的传输层接口
            SDKInterface.CloseInterface(ifHandle);

            // 回收SDK资源
            SDKSystem.Finalize();
            return true;
        }

        public override void SetTriggerMode(TriggerMode triggerMode)
        {
            Feature.SetFeatureEnumValue(remote_handle, "TriggerMode", (long)triggerMode);
        }

        public override void SetTriggerSource(TriggerSource triggerSource)
        {
            string szValue;
            switch (triggerSource)
            {
                case TriggerSource.Software:
                    szValue = "SoftTrigger";
                    break;
                case TriggerSource.DI0:
                case TriggerSource.DI1:
                case TriggerSource.DI2:
                case TriggerSource.DI3:
                    szValue = triggerSource.ToString();
                    break;
                default:
                    return;
            }
            Feature.SetFeatureEnumValueBySymbol(devHandle, "TriggerSource", szValue);
        }

        public override bool TriggerSoftware()
        {
            // 执行软出触发
            // Execute soft trigger
            Feature.ExecuteFeatureCommand(devHandle, "TriggerSoftware");
            return true;
        }

        public override string GetSerialNumber()
        {
            return devSerialNumber;
        }

        public override double GetParameter(string pszFeatureName)
        {
            INOV_Status ret = Feature.GetFeatureFloat(remote_handle, pszFeatureName, out INOV_FEATURE_FLOAT_INFO floatinfo);
            if (ret == INOV_Status.INOV_STATUS_SUCCESS)
            {
                return floatinfo.dCurrentValue;
            }
            return 0;
        }

        public override void SetParameter(string pszFeatureName, double dValue)
        {
            Feature.SetFeatureFloatValue(remote_handle, pszFeatureName, dValue);
        }

        public override bool StartGrab()
        {
            // 开始采集
            Stream.StartAcquisition(dsHandle, INOV_AcquisitionStrategy.INOV_ACQUISITION_STRATEGY_LATEST);
            needStop = false;
            return true;
        }

        public override void StopGrab()
        {
            // 停止采集
            needStop = true;
            Stream.StopAcquisition(dsHandle);
        }

        public override void UserSave()
        {
            Feature.SetFeatureEnumValueBySymbol(remote_handle, "UserSetDefault", "UserSet1");
            Feature.SetFeatureEnumValueBySymbol(remote_handle, "UserSetSelector", "UserSet1");
            Feature.ExecuteFeatureCommand(remote_handle, "UserSetLoad");
        }

        public override void LoadConfigurationFromFile(string szFileName)
        {
            // 导入相机属性文件
            INOV_Status ret = FeatureControl.ImportFeatureFile(devHandle, szFileName);
            if (ret != INOV_Status.INOV_STATUS_SUCCESS)
            {
                return;
            }
        }
    }
}
